<?php
/**
 * 头文件生成类
 * @author Administrator
 *
 */
define ( 'DS', DIRECTORY_SEPARATOR );
class HeaderFile {
	// 数据根目录
	private $basePath = '';
	// 版本文件名
	private $verInfoFilename = 'Version-Info.json';
	// 产品头文件存放路径
	private $headerFilePosition = 'F:\360yunpan\www\git.oschina.net\aliyun-openapi-cpp-sdk\src';
	// 产品头文件扩展名
	private $headerFileSuffix = '.h';
	// 产品源文件存放路径
	private $sourceFilePosition = 'F:\360yunpan\www\git.oschina.net\aliyun-openapi-cpp-sdk\src';
	// 产品源文件扩展名
	private $sourceFileSuffix = '.cc';
	
	// 当前产品目录
	private $curProdPath = '';
	// 当前产品名
	private $curProdName = '';
	
	// 当前产品API版本
	private $curProdAPIVersion = '';
	
	/**
	 * 获取产品目录名
	 * 
	 * @param string $path        	
	 */
	public function getProdPath($path) {
		$this->basePath = $path;
		$arr = null;
		if ($handle = opendir ( $path )) {
			while ( false !== ($file = readdir ( $handle )) ) {
				if ($file != "." && $file != "..") {
					$fileobj = $path . DS . $file;
					if (is_dir ( $fileobj )) { // dir
						$arr [] = $fileobj;
					} else { // file
					}
				}
			}
			closedir ( $handle );
		}
		return $arr;
	}
	
	/**
	 * 生成文件
	 * 
	 * @param array $pathArr        	
	 */
	public function genFiles($pathArr) {
		$arr = null;
		foreach ( $pathArr as $path ) {
			$lastVer = $this->getLastVersionPath ( $path );
			
			$this->curProdPath = $path;
			$this->curProdAPIVersion = $lastVer;
			
			$verInfoFile = $path . DS . $lastVer . DS . $this->verInfoFilename;
			$verInfo = file_get_contents ( $verInfoFile );
			$verInfoArr = json_decode ( $verInfo, true );
			// print_r($verInfoArr);die;
			$prodClassName = $this->genProdClassName ( $verInfoArr ['product'] );
			$arr [] = $prodClassName;
			//$apis = $verInfoArr ['apis'] ['apis'];
			//根据实际有的json文件解析
			$apis = $this->getApis ( $path . DS . $lastVer . DS . 'Api' );
			
			
			// 生成接口头文件
			$apiHeader = $this->genAPIHeaherFile ( $prodClassName, $apis );
			// 生成接口源文件
			$apiSource = $this->genAPISourceFile ( $prodClassName, $apis );
			
			
			
			// 生成头文件
			$this->genProdHeaherFile ( $prodClassName, $apis, $apiHeader );
			// 生成源文件
			$this->genProdSourceFile ( $prodClassName, $apis, $apiSource );
			
			
		}
		return $arr;
	}
	
	/**
	 * 生成头文件
	 * 
	 * @param unknown $prodName        	
	 * @param unknown $apis        	
	 */
	public function genProdHeaherFile($prodClassName, $apis, $apiHeader) {
		$headerTpl = file_get_contents ( './template/prodheader.tpl' );
		// 命名空间
		$ns = 'AliYun' . substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) );
		
		$content = str_replace ( '{upperClassName}', strtoupper ( substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) ).'Service' ), $headerTpl );
		$content = str_replace ( '{upperNamespace}', strtoupper ( $ns ), $content );
		$content = str_replace ( '{coreNS}', 'AliYunCore', $content );
		
		$content = str_replace ( '{className}', $prodClassName, $content );
		$content = str_replace ( '{namespace}', $ns, $content );
		$content = str_replace ( '{requestClasses}', implode('', $apiHeader), $content );
		
		$memberFuncContents = $this->genMemberFuncDefine ( $apis );
		$content = str_replace ( '{memberFunc}', $memberFuncContents, $content );
		$this->writeProdHeaderFile ( $prodClassName, $content );
	}
	
	/**
	 * 生成源文件
	 * 
	 * @param unknown $prodName        	
	 * @param unknown $apis        	
	 */
	public function genProdSourceFile($prodClassName, $apis, $apiSource) {
		$sourceTpl = file_get_contents ( './template/prodsource.tpl' );
		// 命名空间
		$ns = 'AliYun' . substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) );
		$content = str_replace ( '{className}', $prodClassName, $sourceTpl );
		$content = str_replace ( '{namespace}', $ns, $content );
		$content = str_replace ( '{requestClasses}', implode('', $apiSource), $content );
		
		$headerFileName = substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) ).'Service.h';
		$content = str_replace ( '{headerFileName}', $headerFileName, $content );
		
		
		$memberFuncImpl = $this->genMemberFuncImpl ( $prodClassName, $apis );
		$content = str_replace ( '{memberFunc}', $memberFuncImpl, $content );
		$this->writeProdSourceFile ( $prodClassName, $content );
	}
	
	// 生成API头文件
	public function genAPIHeaherFile($prodClassName, $apis) {
		$headerTpl = file_get_contents ( './template/reqheader.tpl' );
		
		$ns = 'AliYun' . substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) );
		$prodName = substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) );
		
		$classes=null;
		foreach ( $apis as $api ) {
			$filename = $this->curProdPath . DS . $this->curProdAPIVersion . DS . 'Api' . DS . $api . '.json';
			// version中有但是无对应json
			if (! file_exists ( $filename ))
				continue;
			
			$apiClassName = $prodName . $api . 'Request';
			$content = str_replace ( '{upperClassName}', strtoupper ( $apiClassName ), $headerTpl );
			$content = str_replace ( '{className}', $apiClassName, $content );
			$content = str_replace ( '{namespace}', $ns, $content );
			$content = str_replace ( '{upperNamespace}', strtoupper ( $ns ), $content );
			$content = str_replace ( '{coreNS}', 'AliYunCore', $content );
			
			$path = 'aliyun-cpp-sdk-' . $this->curProdName;
			if (! file_exists ( $this->headerFilePosition . DS . $path )) {
				mkdir ( $this->headerFilePosition . DS . $path, 0777 );
			}
			$filename = $this->headerFilePosition . DS . $path . DS . $apiClassName . $this->headerFileSuffix;
			//$this->wroteToFile ( $filename, $content );
			$classes[] = $content."\n";
		}
		return $classes;
	}
	
	// 生成API源文件 
	public function genAPISourceFile($prodClassName, $apis) {
		$sourceTpl = file_get_contents ( './template/reqsource.tpl' );
		$ns = 'AliYun' . substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) );
		$prodName = substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) );
		$classes=null;
		foreach ( $apis as $api ) {
			$filename = $this->curProdPath . DS . $this->curProdAPIVersion . DS . 'Api' . DS . $api . '.json';
			// version中有但是无对应json
			if (! file_exists ( $filename ))
				continue;
			//规范格式防止无法解析json
			$apiJSON = file_get_contents ( $filename );
			$order    = array( "\r\n" ,  "\n" ,  "\r", "\t" );
			$replace  =  '' ;
			$apiJSON  =  str_replace ( $order ,  $replace ,  $apiJSON );
			$apiArr = json_decode ( $apiJSON, true );
			$apiClassName = $prodName . $api . 'Request';
			
			$content = str_replace ( '{className}', $apiClassName, $sourceTpl );
			$content = str_replace ( '{namespace}', $ns, $content );
			//生成API请求构造函数实现
			$constructorImpl = $this->genConstructorImpl ( $apiArr );
			
			$content = str_replace ( '{constructorImpl}', $constructorImpl, $content );
			$path = 'aliyun-cpp-sdk-' . $this->curProdName;
			if (! file_exists ( $this->headerFilePosition . DS . $path )) {
				mkdir ( $this->sourceFilePosition . DS . $path, 0777 );
			}
			$filename = $this->sourceFilePosition . DS . $path . DS . $apiClassName . $this->sourceFileSuffix;
			//$this->wroteToFile ( $filename, $content );
			$classes[] = $content."\n";
		}
		return $classes;
	}
	
	/**
	 * 写头文件
	 * 
	 * @param string $prodName        	
	 * @param string $content        	
	 */
	private function writeProdHeaderFile($prodClassName, $content) {
		$path = 'aliyun-cpp-sdk-' . $this->curProdName;
		if (! file_exists ( $this->headerFilePosition . DS . $path )) {
			mkdir ( $this->headerFilePosition . DS . $path, 0777 );
		}
		
		//e.g. EcsService.h/EcsService.cc
		$filename = substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) ).'Service';
		$filename = $this->headerFilePosition . DS . $path . DS . $filename . $this->headerFileSuffix;
		$this->wroteToFile ( $filename, $content );
	}
	/**
	 * 写源文件
	 * 
	 * @param string $prodName        	
	 * @param string $content        	
	 */
	private function writeProdSourceFile($prodClassName, $content) {
		$path = 'aliyun-cpp-sdk-' . $this->curProdName;
		if (! file_exists ( $this->sourceFilePosition . DS . $path )) {
			mkdir ( $this->headerFilePosition . DS . $path, 0777 );
		}
		
		$filename = substr ( $prodClassName, 0, stripos ( $prodClassName, 'client' ) ).'Service';
		$filename = $this->sourceFilePosition . DS . $path . DS . $filename . $this->sourceFileSuffix;
		$this->wroteToFile ( $filename, $content );
	}
	
	/**
	 * 生成标准类名
	 * 
	 * @param string $str        	
	 */
	private function genProdClassName($str) {
		$str = str_replace ( '_', '-', $str );
		$this->curProdName = strtolower ( $str );
		$arr = explode ( '-', $str );
		$name = null;
		foreach ( $arr as $val ) {
			$name .= ucwords ( $val );
		}
		$name .= 'Client';
		return $name;
	}
	
	/**
	 * 获取最新的API最新版本目录
	 * 
	 * @param string $prodPath        	
	 */
	private function getLastVersionPath($prodPath) {
		$subDirs = $this->getSubDirs ( $prodPath );
		$lastVer = max ( $subDirs );
		// return $prodPath . DS . $lastVer;
		return $lastVer;
	}
	
	/**
	 * 获取子目录数组
	 * 
	 * @param string $path        	
	 */
	private function getSubDirs($path) {
		$arr = null;
		if ($handle = opendir ( $path )) {
			while ( false !== ($file = readdir ( $handle )) ) {
				if ($file != "." && $file != "..") {
					$fileobj = $path . DS . $file;
					if (is_dir ( $fileobj )) { // dir
						$arr [] = $file;
					} else { // file
					}
				}
			}
			closedir ( $handle );
		}
		return $arr;
	}
	
	private function getSubFiles($path) {
		$arr = null;
		if ($handle = opendir ( $path )) {
			while ( false !== ($file = readdir ( $handle )) ) {
				if ($file != "." && $file != "..") {
					$fileobj = $path . DS . $file;
					if (is_dir ( $fileobj )) { // dir
						
					} else { // file
						$arr [] = $file;
					}
				}
			}
			closedir ( $handle );
		}
		return $arr;
	}
	
	/**
	 * 生成成员函数定义
	 */
	private function genMemberFuncDefine($apis) {
		$memFunc = null;
		foreach ( $apis as $api ) {
			$memFunc [] = "\tstd::string " . $api . "(const std::string &param);";
		}
		return implode ( PHP_EOL, $memFunc );
	}
	
	/**
	 * 生成成员函数实现
	 */
	private function genMemberFuncImpl($prodName, $apis) {
		$memFunc = null;
		foreach ( $apis as $api ) {
			$memFunc [] = "string $prodName::" . $api . "(const string &param){
	
	return typeid(*this).name();
}";
		}
		return implode ( PHP_EOL, $memFunc );
	}
	
	/**
	 * 写文件
	 * 
	 * @param unknown $filename        	
	 * @param unknown $content        	
	 */
	private function wroteToFile($filename, $content) {
		$fp = @fopen ( $filename, 'w' );
		if (flock ( $fp, LOCK_EX )) { // 进行排它型锁定
			fwrite ( $fp, $content );
			flock ( $fp, LOCK_UN ); // 释放锁定
		}
		fclose ( $fp );
	}
	
	/**
	 * 获取api数组
	 * @param unknown $path
	 */
	private function getApis($path) {
		$apiFiles = $this->getSubFiles ( $path );
		foreach ( $apiFiles as $k => $v ) {
			$apiFiles [$k] = substr ( $v, 0, strpos ( $v, '.' ) );
		}
		return $apiFiles;
	}
	
	/**
	 * 生成API请求构造函数实现
	 * @param unknown $arr
	 */
	private function genConstructorImpl($arr) {
		$code [] = "//set the default value of the public parameters. \n";
		$httpMethod = stripos ( $arr ['isvProtocol'] ['method'], 'GET' ) !== false ? 'GET' : $arr ['isvProtocol'] ['method'];
		$code [] = "\tthis->HttpMethod = \"" . $httpMethod . "\";\n";
		
		$protocol = $arr ['isvProtocol'] ['protocol']=='HTTPS'?'HTTPS':'HTTP';
		$code [] = "\tthis->Protocol = \"" . $protocol . "\";\n";
		
		$code [] = "\tthis->Domain = \"\";\n";
		
		$pattern = isset ( $arr ['isvProtocol'] ['pattern'] ) ? $arr ['isvProtocol'] ['pattern'] : '';
		$code [] = "\tthis->Path = \"" . $pattern . "\";\n";
		
		$ProductName = strtolower(str_replace ( '_', '-', $arr ['product'] ));
		$code [] = "\tthis->ProductName = \"" . $ProductName . "\";\n";
		
		$code [] = "\tthis->Action = \"" . $arr ['name'] . "\";\n";
		$code [] = "\tthis->Version = \"" . $arr ['version'] . "\";\n";
		$code [] = "\tthis->Format = \"JSON\";\n";
		$code [] = "\tthis->SignatureMethod = \"HMAC-SHA1\";\n";
		$code [] = "\tthis->SignatureVersion = \"1.0\";\n";
		
		
		$code [] = "\t\n";
		$code [] = "\t//set the position and default value for the business parameters. \n";
		$params = $arr ['parameters'] ['parameters'];
		foreach ( $params as $param ) {
			$code [] = "\tthis->KVMap[\"" . $param ['tagName'] . "\"] = \"\";\n";
			$code [] = "\tthis->KPMap[\"" . $param ['tagName'] . "\"] = \"" . $param ['tagPosition'] . "\";\n";
		}
		
		return implode ( '', $code );
	}
	
}

